﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

    using DanielsGameLibrary;
    public class ToTargetRender
    {
        protected RenderTarget2D RenderTarget;
        protected Texture2D TargetMap;
        protected VertexPositionTexture[] fullScreenVertices;

        public ToTargetRender(GraphicsDevice device)
        { 
            PresentationParameters pp = device.PresentationParameters;
            RenderTarget = new RenderTarget2D(device, pp.BackBufferWidth, pp.BackBufferHeight, 
                                              true, device.DisplayMode.Format, DepthFormat.Depth24);

            fullScreenVertices = SetUpFullscreenVertices();
        }

        public ToTargetRender(GraphicsDevice device, Vector2 resolution)
        {
            PresentationParameters pp = device.PresentationParameters;
            RenderTarget = new RenderTarget2D(device, (int)resolution.X, (int)resolution.Y,
                                              true, device.DisplayMode.Format, DepthFormat.Depth24);

            fullScreenVertices = SetUpFullscreenVertices();
        }

        protected VertexPositionTexture[] SetUpFullscreenVertices()
        {
            VertexPositionTexture[] vertices = new VertexPositionTexture[4];

            vertices[0] = new VertexPositionTexture(new Vector3(-1, 1, 0f), new Vector2(0, 1));
            vertices[1] = new VertexPositionTexture(new Vector3(1, 1, 0f), new Vector2(1, 1));
            vertices[2] = new VertexPositionTexture(new Vector3(-1, -1, 0f), new Vector2(0, 0));
            vertices[3] = new VertexPositionTexture(new Vector3(1, -1, 0f), new Vector2(1, 0));

            return vertices;
        }
    }

    public class PerlinNoiseGenerater : ToTargetRender
    {
        Texture2D staticmap;

        public PerlinNoiseGenerater(GraphicsDevice device, int staticMapResolution)
            : base(device)
        { 
            staticmap = CreateStaticMap(device, staticMapResolution);

        }

        public PerlinNoiseGenerater(GraphicsDevice device, Vector2 resolution, int staticMapResolution)
            : base(device, resolution)
        {
            staticmap = CreateStaticMap(device, staticMapResolution);
        }

        private Texture2D CreateStaticMap(GraphicsDevice device, int resolution)
        {
            Random rand = new Random();
            Color[] noisyColors = new Color[resolution * resolution];
            for (int x = 0; x < resolution; x++)
                for (int y = 0; y < resolution; y++)
                    noisyColors[x + y * resolution] = new Color(new Vector3((float)rand.Next(1000) / 1000.0f, 0, 0));

            Texture2D noiseImage = new Texture2D(device, resolution, resolution);
            noiseImage.SetData(noisyColors);
            return noiseImage;
        }

        public Texture2D GeneratePerlinNoise(GraphicsDevice device, Effect effect, float time,Vector2 speed, float overcast)
        {
            device.SetRenderTarget(RenderTarget);
            device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);

            effect.CurrentTechnique = effect.Techniques["PerlinNoise"];
            effect.Parameters["xTexture0"].SetValue(staticmap);
            effect.Parameters["xOvercast"].SetValue(overcast);
            effect.Parameters["xTime"].SetValue(time / 50000.0f);

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();


                device.DrawUserPrimitives(PrimitiveType.TriangleStrip, fullScreenVertices, 0, 2);


            }

            device.SetRenderTarget(null);

            return TargetMap = (Texture2D)RenderTarget;
        }

    }
    
    public class refractionRender : ToTargetRender
    {
        

        public refractionRender(GraphicsDevice device)
            : base(device)
        {


        }

        public refractionRender(GraphicsDevice device, Vector2 resolution)
            : base(device, resolution)
        {

        }

      
        private Texture2D DrawRefractionMap(GraphicsDevice device, Vector4 Plane,  Camera cam, GameTime time,
                                            drawSceneDelegate drawscene)
        {

            device.SetRenderTarget(RenderTarget);
            device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);
            //DrawTerrain(viewMatrix, "MultiTextured", true, Plane);
            //drawscene(device,cam, time, true, Math3D.CreatePlane(0, Vector3.Up, true));

            device.SetRenderTarget(null);

            return TargetMap = (Texture2D)RenderTarget;

        }

    }

    public class ReflectionRender : ToTargetRender
    {


        public ReflectionRender(GraphicsDevice device)
            : base(device)
        {


        }

        public ReflectionRender(GraphicsDevice device, Vector2 resolution)
            : base(device, resolution)
        {

        }

        public static Matrix getReflectionViewM(Camera cam, Vector4 plane)
        {



            Vector3 reflCameraPosition = cam.position;
            reflCameraPosition.Y = -cam.position.Y + plane.W * 2;

            Vector3 reflTargetPos = cam.position + cam.angle;
            reflTargetPos.Y = -(cam.position.Y + cam.angle.Y) + plane.W * 2;

            Vector3 cameraRight = Vector3.Transform(new Vector3(1, 0, 0), Matrix.CreateRotationX(cam.angle.X) * Matrix.CreateRotationY(cam.angle.Y));
            Vector3 invUpVector = Vector3.Cross(cameraRight, reflTargetPos - reflCameraPosition);



            return Matrix.CreateLookAt(reflCameraPosition, reflTargetPos, invUpVector); ;
        }


        public Texture2D DrawReflectionMap(GraphicsDevice device, Vector4 plane, Camera cam, GameTime time,
                                            drawSceneDelegate drawscene)
        {
            ///////////update reflection view matrix
            Matrix refwiev = getReflectionViewM(cam, plane);
            Camera refcam = new Camera(null, 0f, 0f, 0f);
            refcam.ViewMatrix = refwiev;
            refcam.ProjectionMatrix = cam.ProjectionMatrix;
            ///////////////////////////////////////////

            device.SetRenderTarget(RenderTarget);
            device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);

            drawscene(device, refcam, time, true, plane);
            

            device.SetRenderTarget( null);
            return TargetMap = (Texture2D)RenderTarget;
        }

    }

